package com.itwn.portal.controller;

import cn.hutool.core.bean.BeanUtil;
import com.itwn.common.constant.RedisConst;
import com.itwn.portal.common.exception.Asserts;
import com.itwn.portal.common.result.BusinessCode;
import com.itwn.portal.model.entity.User;
import com.itwn.portal.model.vo.LoginRequest;
import com.itwn.portal.model.vo.UserVo;
import com.itwn.portal.service.UserService;
import com.itwn.portal.util.JwtUtil;
import com.itwn.portal.util.SmsUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.Duration;
import java.util.*;

@RestController
@RequestMapping("/user")
@Api(tags = "用户模块")
@Slf4j
public class UserController {

    @Autowired
    private UserService userService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private SmsUtil smsUtil;

    @ApiOperation("账号密码登录")
    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest param, HttpServletRequest request) {
        UserVo userVo = userService.login(param);
        return ResponseEntity.ok()
                .header("Authorization", userVo.getToken())
                //告知浏览器可以访问 Authorization 响应头，否则访问不了
                .header("Access-Control-Expose-Headers", "Authorization")
                .body(userVo);
    }


    /**
     * 图片验证码
     */
    @GetMapping("/code")
    @ApiOperation("生成图片验证码")
    public ResponseEntity generateCaptcha() throws IOException {
        //2) 创建缓存图片：指定宽
        int width = 110, height = 45;
        //参数3：图片的类型，使用RGB类型
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        //3) 获取画笔对象
        Graphics graphics = image.getGraphics();
        //4) 设置画笔颜色，并且填充矩形区域
        graphics.setColor(Color.WHITE);
        graphics.fillRect(0, 0, width, height);
        //创建一个StringBuider对象
        StringBuilder sb = new StringBuilder();
        //5) 从字符数组中随机得到字符
        String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        char[] arr = characters.toCharArray();

        Random random = new Random();

        for (int i = 0; i < 4; i++) {
            //随机从0到长度之间去取索引
            int index = random.nextInt(arr.length);
            //得到1个字符
            char c = arr[index];
            sb.append(c);
            //6) 设置字体，大小为22，设置字的颜色随机
            graphics.setFont(new Font(null, Font.BOLD + Font.ITALIC, 22));
            graphics.setColor(getColor());
            //7) 将每个字符画到图片，位置：5+(i*23), 25
            //将字符转成字符串
            graphics.drawString(String.valueOf(c), 5 + (i * 23), 25);
        }

        //8) 画干扰线8条线，线的位置是随机的，x范围在width之中，y的范围在height之中。
        for (int i = 0; i < 10; i++) {
            graphics.setColor(getColor());
            int x1 = random.nextInt(width);
            int y1 = random.nextInt(height);
            int x2 = random.nextInt(width);
            int y2 = random.nextInt(height);
            graphics.drawLine(x1, y1, x2, y2);
        }
        //9) 将缓存的图片输出到响应输出流中
        //参数1：要输出的缓存图片，参数2：格式，参数3：输出到哪个流中
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(image, "jpeg", outputStream);

        //随机生成一个key，前面加上code::
        String key = RedisConst.USER_VALIDATE_CODE + ":" + UUID.randomUUID().toString().replace("-", "");
        //得到验证码，将生成的字符串放到Redis中，键随机生成，10分钟过期
        redisTemplate.opsForValue().set(key, sb.toString(), Duration.ofMinutes(10));

        log.info("生成的验证码为：{}，Redis中的key是：{}", sb, key);

        Base64.Encoder encoder = Base64.getEncoder();
        String base64Img = "data:image/jpeg;base64," + encoder.encodeToString(outputStream.toByteArray());
        //返回的数据包含验证码的key和图片
        Map<String, String> data = new HashMap<>();
        data.put("key", key);  //redis中键
        data.put("base64Img", base64Img);  //图片
        //返回key和图片的base64的编码
        return ResponseEntity.ok(data);
    }

    //写一个方法随机获取颜色
    private Color getColor() {
        Random random = new Random();
        //红，绿，蓝取值0-255，随机生成 0-255之间数
        int r = random.nextInt(256);
        int g = random.nextInt(256);
        int b = random.nextInt(256);
        return new Color(r, g, b);
    }

    /**
     * 前端请求数据格式，token = "Bearer xxxxx"
     *
     * @param authorization
     * @return
     */
    @ApiOperation("判断用户是否登录")
    @GetMapping("/isLogged")
    public ResponseEntity<UserVo> isLogged(@RequestHeader("Authorization") String authorization) {
        // 判断token是否为空
        Asserts.error(Objects.isNull(authorization), BusinessCode.USER_NOT_LOGGED);
        // 校验token
        boolean isValid = jwtUtil.validateToken(authorization);
        Asserts.error(!isValid, BusinessCode.INVALID_TOKEN);

        // 获取用户id
        String id = jwtUtil.getValue(authorization, "id");
        User user = userService.findById(Long.parseLong(id));
        // 返回UserVo对象
        UserVo userVo = BeanUtil.copyProperties(user, UserVo.class);
        return ResponseEntity.ok(userVo);
    }

    @ApiOperation("退出")
    @DeleteMapping("/logout")
    public ResponseEntity<?> logout(@RequestHeader("Authorization") String token) {
        // 判断token是否为空
        Asserts.error(Objects.isNull(token), BusinessCode.USER_NOT_LOGGED);
        // 获取用户id
        String id = jwtUtil.getValue(token, "id");
        // 删除Redis中token
        redisTemplate.delete(RedisConst.USER_TOKEN_PREFIX + ":" + id);
        return ResponseEntity.ok(null);
    }





    /**
     * 手机号发短信
     */
    @GetMapping("/sendSms/{telephone}")
    @ApiOperation("手机号发短信")
    public ResponseEntity<String> sendSms(@PathVariable("telephone") String telephone) {

        //1、生成四位随机数字
        String code = RandomStringUtils.randomNumeric(4);
        //2、调用阿里云Api，发送短信
        //String result = smsUtil.sendSms(telephone, code);
        String result = "OK"; // 方便测试
        //3、判断是否发送成功
        Asserts.error(!"OK".equalsIgnoreCase(result), BusinessCode.SMS_SEND_ERROR);
        //4、将验证码存储到Redis中
        redisTemplate.opsForValue().set(RedisConst.SHORT_MESSAGE_SERVICE + ":" + telephone, code, Duration.ofMinutes(10));
        String response = "给手机号：" + maskPhoneNumber(telephone) + "成功发送验证码";
        return ResponseEntity.ok(response);
    }

    /**
     * 隐藏手机号码中间四位
     * @param telephone
     * @return
     */
    private String maskPhoneNumber(String telephone) {
        return telephone.substring(0, 3) + "****" + telephone.substring(7);
    }

    /**
     * 手机短信验证码登录
     */
    @ApiOperation("手机短信验证码登录")
    @PostMapping("/smsLogin")
    public ResponseEntity<?> smsLogin(@RequestBody LoginRequest param, HttpServletRequest request) {
        UserVo userVo = userService.smsLogin(param);
        return ResponseEntity.ok()
                .header("Authorization", userVo.getToken())
                //告知浏览器可以访问 Authorization 响应头，否则访问不了
                .header("Access-Control-Expose-Headers", "Authorization")
                .body(userVo);
    }
}
